using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace PKGames.Audio
{
	[RequireComponent(typeof(AudioListener))]
	public class AudioManager : MonoSingleton<AudioManager>
	{
		private enum BgmState
		{
			Idle,
			FadeOut,
			FadeIn
		}

		private const float MAX_VOLUME = 1f;

		private const int AudioPoolSize = 9;

		private List<AudioSource> _audioSources = new List<AudioSource>();

		private List<AudioSource> _dynamicAudioSources = new List<AudioSource>();

		private List<AudioDataCollection> _audioDataCollections = new List<AudioDataCollection>();

		private AudioSource _backgroundAudioSource;

		private AudioClip _nextBackgroundMusic;

		[SerializeField]
		private AudioClip _bgm;

		private AudioDataCollection _sharedAudioDataCollection;

		[SerializeField]
		private float _bgmVolume = 0.5f;

		private List<AudioSourceData> _playingAudioList = new List<AudioSourceData>();

		private List<AudioSourceData> _stoppedAudioList = new List<AudioSourceData>();

		private AudioListener _audioListener;

		private bool _disableAfterFadeOut;

		private AudioClip _currentBgm;

		private string _sceneLoaded;

		private BgmState _bgmState;

		public List<AudioDataCollection> AudioDataCollections => _audioDataCollections;

		protected override void Awake()
		{
			base.Awake();
			_backgroundAudioSource = base.gameObject.AddComponent<AudioSource>();
			_audioListener = GetComponent<AudioListener>();
			_currentBgm = _bgm;
			LoadPool();
		}

		private void Update()
		{
			UpdateBgm();
			foreach (AudioSourceData playingAudio in _playingAudioList)
			{
				if (!playingAudio.IsPlaying())
				{
					playingAudio.EndSoundNotification();
					_stoppedAudioList.Add(playingAudio);
				}
			}
			foreach (AudioSourceData stoppedAudio in _stoppedAudioList)
			{
				_playingAudioList.Remove(stoppedAudio);
			}
			_stoppedAudioList.Clear();
		}

		private void UpdateBgm()
		{
			if (!(_nextBackgroundMusic != null))
			{
				return;
			}
			if (_bgmState == BgmState.FadeOut)
			{
				if (_backgroundAudioSource.volume > 0f)
				{
					_backgroundAudioSource.volume -= 0.03f;
				}
				else
				{
					_backgroundAudioSource.volume = 0f;
					_backgroundAudioSource.Stop();
					_bgmState = BgmState.FadeIn;
					if (_disableAfterFadeOut)
					{
						SetAudioListenerActive(isEnabled: false);
					}
				}
			}
			if (_bgmState == BgmState.FadeIn)
			{
				if (_backgroundAudioSource.clip != _nextBackgroundMusic)
				{
					_backgroundAudioSource.loop = true;
					_backgroundAudioSource.clip = _nextBackgroundMusic;
					_backgroundAudioSource.volume = 0f;
					_backgroundAudioSource.Play();
				}
				if (_backgroundAudioSource.volume < _bgmVolume)
				{
					_backgroundAudioSource.volume += 0.03f;
					return;
				}
				_backgroundAudioSource.volume = _bgmVolume;
				_nextBackgroundMusic = null;
			}
		}

		private void LoadPool()
		{
			for (int i = 0; i < 9; i++)
			{
				AudioSource item = base.gameObject.AddComponent<AudioSource>();
				_audioSources.Add(item);
			}
		}

		public bool IsBackgroundMusicPlaying()
		{
			return _backgroundAudioSource.isPlaying;
		}

		public void PlayBackgroundMusic()
		{
			if (_currentBgm != null)
			{
				PlayBackgroundMusic(_currentBgm);
			}
		}

		private void PlayBackgroundMusic(AudioClip bgm)
		{
			if (_backgroundAudioSource.clip == null || (_backgroundAudioSource.clip != bgm && bgm != _nextBackgroundMusic))
			{
				StopAllCoroutines();
				_nextBackgroundMusic = bgm;
				if (_backgroundAudioSource.isPlaying)
				{
					_bgmState = BgmState.FadeOut;
				}
				else
				{
					_bgmState = BgmState.FadeIn;
				}
			}
			else if (_backgroundAudioSource.clip == bgm)
			{
				PlayCurrentBackgroundMusic();
			}
		}

		public void PlayCurrentBackgroundMusic()
		{
			StopAllCoroutines();
			if (!_backgroundAudioSource.isPlaying)
			{
				_backgroundAudioSource.volume = 0f;
				StartCoroutine(VolumeFadeIn(_bgmVolume));
				_backgroundAudioSource.Play();
			}
			else if (_backgroundAudioSource.volume == 0f)
			{
				StopBackgroundMusic();
				_backgroundAudioSource.volume = _bgmVolume;
				PlayBackgroundMusic();
			}
		}

		public void StopBackgroundMusic()
		{
			_nextBackgroundMusic = null;
			_bgmState = BgmState.Idle;
			_backgroundAudioSource.Stop();
		}

		public void StopBackgroundWithFade(bool disableAfterFade)
		{
			StopAllCoroutines();
			_disableAfterFadeOut = disableAfterFade;
			_nextBackgroundMusic = null;
			_bgmState = BgmState.Idle;
			StartCoroutine(StopBackgroundWithFade(0f));
		}

		private IEnumerator StopBackgroundWithFade(float finalVolume)
		{
			yield return StartCoroutine(VolumeFadeOut(finalVolume));
			StopBackgroundMusic();
		}

		public void DecreaseBackgroundVolumeWithFade(float volume)
		{
			StopAllCoroutines();
			StartCoroutine(VolumeFadeOut(volume));
		}

		public void IncreaseBackgroundVolumeWithFade(float volume)
		{
			StopAllCoroutines();
			StartCoroutine(VolumeFadeIn(volume));
		}

		public void SetBackgroundVolume(float volume)
		{
			_bgmVolume = volume;
		}

		public AudioSource PlayUnique(string id)
		{
			StopCurrentAudioDataCollection();
			return Play(id);
		}

		public AudioSource PlayIfUnique(string id)
		{
			if (!SoundPlaying())
			{
				return Play(id);
			}
			return null;
		}

		public AudioSource PlayIfDifferent(string id, bool loop = false)
		{
			if (!SoundPlaying(id))
			{
				return Play(id, null, loop);
			}
			return null;
		}

		public AudioSource Play(string id, bool loop = false, float pitch = 1f)
		{
			AudioSource audioSource = Play(id, null, loop);
			if (audioSource != null)
			{
				audioSource.pitch = pitch;
			}
			return audioSource;
		}

		public AudioSource StopOthersAndPlay(string id, bool loop = false)
		{
			foreach (AudioSourceData playingAudio in _playingAudioList)
			{
				playingAudio.StopAudio();
			}
			return Play(id, null, loop);
		}

		public AudioSource Play(string id, Action<string> endSoundNotification, bool loop = false)
		{
			AudioSource audioSource = GetAudioSource();
			if (audioSource != null)
			{
				audioSource.loop = loop;
				AudioData audioDataById = GetAudioDataById(id);
				if (audioDataById != null)
				{
					audioSource.clip = audioDataById.Audio;
					if (audioSource.clip != null)
					{
						audioSource.volume = audioDataById.Volume * 1f;
						audioSource.Play();
						_playingAudioList.Add(new AudioSourceData(id, audioSource, endSoundNotification));
						return audioSource;
					}
				}
			}
			return null;
		}

		public AudioSource PlayWithDynamicAudioSource(string id)
		{
			AudioSource dynamicAudioSource = GetDynamicAudioSource();
			if (dynamicAudioSource != null)
			{
				dynamicAudioSource.loop = false;
				AudioData audioDataById = GetAudioDataById(id);
				if (audioDataById != null)
				{
					dynamicAudioSource.clip = audioDataById.Audio;
					if (dynamicAudioSource.clip != null)
					{
						dynamicAudioSource.volume = audioDataById.Volume * 1f;
						dynamicAudioSource.Play();
						return dynamicAudioSource;
					}
				}
			}
			return null;
		}

		public AudioSource GetDynamicAudioSource()
		{
			foreach (AudioSource dynamicAudioSource in _dynamicAudioSources)
			{
				if (!dynamicAudioSource.isPlaying)
				{
					return dynamicAudioSource;
				}
			}
			AudioSource audioSource = base.gameObject.AddComponent<AudioSource>();
			_dynamicAudioSources.Add(audioSource);
			return audioSource;
		}

		public void StopWithFadeOut(string id, float fadeTime)
		{
			StartCoroutine(FadeOutAudioSource(id, fadeTime));
		}

		private IEnumerator FadeOutAudioSource(string id, float fadeTime)
		{
			AudioSource audioSource = GetAudioSourceById(id);
			if (audioSource != null)
			{
				float currentTime = 0f;
				float initialVolume = audioSource.volume;
				while (currentTime < fadeTime)
				{
					audioSource.volume = initialVolume * (1f - currentTime / fadeTime);
					currentTime += Time.deltaTime;
					yield return new WaitForSeconds(0.01f);
				}
				audioSource.Stop();
			}
			else
			{
				UnityEngine.Debug.LogWarning("Could Not Stop Audio Clip: " + id);
			}
		}

		public void StopCurrentAudioDataCollection()
		{
			foreach (AudioDataCollection audioDataCollection in _audioDataCollections)
			{
				AudioData[] sounds = audioDataCollection.Sounds;
				int num = 0;
				goto IL_0044;
				IL_003e:
				num++;
				goto IL_0044;
				IL_0044:
				if (num < sounds.Length)
				{
					AudioData audioData = sounds[num];
					Stop(audioData.Id);
					break;
				}
			}
		}

		public void Stop(string id)
		{
			AudioSource audioSourceById = GetAudioSourceById(id);
			if (audioSourceById != null)
			{
				audioSourceById.Stop();
			}
		}

		public AudioSource GetAudioSource()
		{
			foreach (AudioSource audioSource in _audioSources)
			{
				if (!audioSource.isPlaying)
				{
					return audioSource;
				}
			}
			return null;
		}

		private bool SoundPlaying()
		{
			foreach (AudioSource audioSource in _audioSources)
			{
				if (audioSource.isPlaying)
				{
					return true;
				}
			}
			return false;
		}

		public bool SoundPlaying(string id)
		{
			foreach (AudioSourceData playingAudio in _playingAudioList)
			{
				if (string.Equals(playingAudio.Id, id))
				{
					return true;
				}
			}
			return false;
		}

		public AudioData GetAudioDataById(string id)
		{
			AudioData audioData = null;
			if (audioData == null && _sharedAudioDataCollection != null)
			{
				audioData = _sharedAudioDataCollection.GetAudioDataById(id);
			}
			if (audioData == null)
			{
				audioData = GetAudioFromAudioDataCollections(id);
			}
			if (audioData == null)
			{
				UnityEngine.Debug.Log("Audio error. Clip not found: " + id);
			}
			return audioData;
		}

		private AudioData GetAudioFromAudioDataCollections(string id)
		{
			AudioData audioData = null;
			foreach (AudioDataCollection audioDataCollection in _audioDataCollections)
			{
				audioData = audioDataCollection.GetAudioDataById(id);
				if (audioData != null)
				{
					return audioData;
				}
			}
			return audioData;
		}

		public AudioSource GetAudioSourceById(string id)
		{
			AudioData audioDataById = GetAudioDataById(id);
			if (audioDataById != null)
			{
				AudioClip audio = audioDataById.Audio;
				AudioSource result = null;
				if (audio != null)
				{
					foreach (AudioSource audioSource in _audioSources)
					{
						if (audioSource != null && audioSource.clip != null && audioSource.clip.name.Equals(audio.name) && audioSource.isPlaying)
						{
							return audioSource;
						}
					}
					return result;
				}
				return result;
			}
			return null;
		}

		public void StopAllSounds()
		{
			if (_backgroundAudioSource.isPlaying)
			{
				_backgroundAudioSource.Stop();
			}
			StopAudioSourceList(_audioSources);
			StopAudioSourceList(_dynamicAudioSources);
		}

		public void StopAllSoundExceptBGM()
		{
			foreach (AudioSourceData playingAudio in _playingAudioList)
			{
				if (playingAudio.IsPlaying())
				{
					playingAudio.StopAudio();
				}
			}
		}

		public void StopAllSoundsExcept(string id)
		{
			foreach (AudioSourceData playingAudio in _playingAudioList)
			{
				if (playingAudio.IsPlaying() && !playingAudio.Id.Equals(id))
				{
					playingAudio.StopAudio();
				}
			}
		}

		private void StopAudioSourceList(List<AudioSource> list)
		{
			foreach (AudioSource item in list)
			{
				if (item.isPlaying)
				{
					item.Stop();
				}
			}
		}

		public void StopIfPlaying(string id)
		{
			if (SoundPlaying(id))
			{
				Stop(id);
			}
		}

		public void Cleanup()
		{
			StopAllCoroutines();
			_backgroundAudioSource.clip = null;
			CleanupSourceList(_audioSources);
			CleanupSourceList(_dynamicAudioSources);
		}

		private void CleanupSourceList(List<AudioSource> list)
		{
			foreach (AudioSource item in list)
			{
				item.clip = null;
			}
		}

		public IEnumerator VolumeFadeIn(float volume)
		{
			float maxVolume = volume * 1f;
			SetAudioListenerActive(isEnabled: true);
			while (_backgroundAudioSource.volume < volume && _backgroundAudioSource.volume < maxVolume)
			{
				_backgroundAudioSource.volume += 0.01f;
				yield return new WaitForSeconds(0.01f);
			}
			_backgroundAudioSource.volume = maxVolume;
		}

		public IEnumerator VolumeFadeOut(float volume)
		{
			while (_backgroundAudioSource.volume > volume && _backgroundAudioSource.volume >= 0f)
			{
				_backgroundAudioSource.volume -= 0.01f;
				yield return new WaitForSeconds(0.01f);
			}
			_backgroundAudioSource.volume = 0f;
			if (_disableAfterFadeOut)
			{
				_disableAfterFadeOut = false;
				SetAudioListenerActive(isEnabled: false);
			}
		}

		public void SetMute(bool mute)
		{
			_backgroundAudioSource.mute = mute;
			foreach (AudioSource audioSource in _audioSources)
			{
				audioSource.mute = mute;
			}
		}

		public void RegisterAudioDataCollection(AudioDataCollection collection)
		{
			_audioDataCollections.Add(collection);
		}

		public void UnregisterAudioDataCollection(AudioDataCollection collection)
		{
			_audioDataCollections.Remove(collection);
		}

		public void RegisterAudioDataCollectionBgm(AudioClip clip)
		{
			_currentBgm = clip;
		}

		public void UnregisterAudioDataCollectionBgm()
		{
			_currentBgm = _bgm;
		}

		public void SetAudioListenerActive(bool isEnabled)
		{
			if (_audioListener != null)
			{
				_audioListener.enabled = isEnabled;
			}
		}
	}
}
